package admin

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"math"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"
	. "xm_shop/database"
	. "xm_shop/models"
	. "xm_shop/utils"
)

// 并发控制器
var wg sync.WaitGroup

type GoodsController struct{}

// 富文本编辑器上传的图片
func (g GoodsController) ImageUpload(context *gin.Context) {
	// 判断oss上传是否开启
	if GetOssStatus() != 1 {
		// 获取上传的图片
		file, err5 := context.FormFile("file")
		if err5 != nil {
			context.String(http.StatusBadRequest, "文件上传失败")
			return
		}
		fmt.Println(file.Filename)
		// 获取文件后缀
		extName := path.Ext(file.Filename)
		// 创建合法后缀map映射
		allowExtMap := map[string]bool{
			".jpg":  true,
			".jpeg": true,
			".png":  true,
			".gif":  true,
		}
		// 判断文件的合法性
		if _, ok := allowExtMap[extName]; !ok {
			context.String(http.StatusBadRequest, "文件不合法")
			return
		}
		// 获取当前日期
		day := time.Now().Format("20060102")
		// 指定文件存储目录
		dir := "./static/upload/" + day
		// 迭代创建目录
		os.MkdirAll(dir, 0666)
		// 获取当前时间戳的字符串形式
		fileName := strconv.FormatInt(time.Now().Unix(), 10) + extName // 不要忘记拼接后缀
		// 拼接文件路径
		dst := path.Join(dir, fileName)
		err6 := context.SaveUploadedFile(file, dst)
		if err6 != nil {
			context.String(http.StatusBadRequest, "文件保存失败")
			return
		}
		if GetOssStatus() != 1 { // 要保存到本地的图片才做裁剪
			wg.Add(1)
			go func() {
				defer wg.Done()
				ResizeGoodsImage(dst)
			}()
		}
		context.JSON(http.StatusOK, gin.H{
			"link": dst, // 这里路径不规范, 应该是 /path/to/image.jpg
		})
	} else {
		src, err := OssUploadImg(context, "file")
		if err != nil {
			context.String(http.StatusBadRequest, "文件上传失败")
			return
		}
		context.JSON(http.StatusOK, gin.H{
			"success": true,
			"url":     GetSettingFromColumn("OssDomain") + src,
		})
	}
}

// 获取所有的颜色信息
func (g GoodsController) GetAllColor(context *gin.Context) {
	var goodsColorList []GoodsColor
	DB.Find(&goodsColorList)
	context.JSON(http.StatusOK, gin.H{
		"colorList": goodsColorList,
	})
}

// 保存商品信息
func (g GoodsController) Add(context *gin.Context) {
	// 1. 获取表单提交的数据
	title := context.PostForm("title")
	subTitle := context.PostForm("sub_title")
	goodsSn := context.PostForm("goods_sn")
	cateId, err1 := strconv.Atoi(context.PostForm("cate_id"))
	goodsNumber, err2 := strconv.Atoi(context.PostForm("goods_number"))
	price, err3 := strconv.ParseFloat(context.PostForm("price"), 64) // 将字符型转成float64类型的数据
	marketPrice, err4 := strconv.ParseFloat(context.PostForm("market_price"), 64)
	relationGoods := context.PostForm("relation_goods")
	goodsAttr := context.PostForm("goods_attr") // 额外属性
	goodsVersion := context.PostForm("goods_version")
	goodsGift := context.PostForm("goods_gift")
	goodsFitting := context.PostForm("goods_fitting")
	// 获取到的是切片
	goodsColor := context.PostFormArray("goods_color")
	goodsKeywords := context.PostForm("goods_keywords")
	goodsDesc := context.PostForm("goods_desc")
	goodsContent := context.PostForm("goods_content")
	isDelete, err5 := strconv.Atoi("is_delete")
	isHot, err6 := strconv.Atoi(context.PostForm("is_hot"))
	isBest, err7 := strconv.Atoi(context.PostForm("is_best"))
	isNew, err8 := strconv.Atoi(context.PostForm("is_new"))
	goodsTypeID, err9 := strconv.Atoi(context.PostForm("goods_type_id"))
	sort, err10 := strconv.Atoi(context.PostForm("sort"))
	status, err11 := strconv.Atoi(context.PostForm("status"))
	if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil || err7 != nil || err8 != nil || err9 != nil || err10 != nil || err11 != nil {
		context.String(http.StatusBadRequest, "参数有误")
		return
	}
	// 2. 获取颜色信息, 将颜色转化成字符串
	goodsColorStr := strings.Join(goodsColor, ",") // 将goodsColor切片里面的元素按照","进行拼接成字符串
	// 3. 上传图片, 生成缩略图
	goodsImg, err12 := context.FormFile("goods_img")
	if err12 != nil {
		context.String(http.StatusBadRequest, "文件上传失败")
		return
	}
	fmt.Println(goodsImg.Filename)
	// 获取文件后缀
	extName := path.Ext(goodsImg.Filename)
	// 创建合法后缀map映射
	allowExtMap := map[string]bool{
		".jpg":  true,
		".jpeg": true,
		".png":  true,
		".gif":  true,
	}
	// 判断文件的合法性
	if _, ok := allowExtMap[extName]; !ok {
		context.String(http.StatusBadRequest, "文件不合法")
		return
	}
	// 获取当前日期
	day := time.Now().Format("20060102")
	// 指定文件存储目录
	dir := "./static/upload/" + day
	// 迭代创建目录
	os.MkdirAll(dir, 0666)
	// 获取当前时间戳的字符串形式
	fileName := strconv.FormatInt(time.Now().Unix(), 10) + extName // 不要忘记拼接后缀
	// 拼接文件路径
	dst := path.Join(dir, fileName)
	err13 := context.SaveUploadedFile(goodsImg, dst)
	if err13 != nil {
		context.String(http.StatusBadRequest, "文件保存失败")
		return
	}
	if GetOssStatus() != 1 { // 上传到云存储的图片不做裁剪
		// 对保存到本地的图片做裁剪
		wg.Add(1)
		go func() {
			ResizeGoodsImage(dst)
			wg.Done()
		}()
	}
	// 4. 增加商品数据
	goods := Goods{
		Title:         title,
		SubTitle:      subTitle,
		GoodsSn:       goodsSn,
		CateID:        cateId,
		GoodsNumber:   goodsNumber,
		Price:         price,
		MarketPrice:   marketPrice,
		RelationGoods: relationGoods,
		GoodsColor:    goodsColorStr,
		GoodsKeywords: goodsKeywords,
		GoodsDesc:     goodsDesc,
		GoodsImg:      dst,
		IsDelete:      isDelete,
		IsHot:         isHot,
		IsBest:        isBest,
		IsNew:         isNew,
		GoodsAttr:     goodsAttr, // 额外属性
		GoodsVersion:  goodsVersion,
		GoodsGift:     goodsGift,
		GoodsFitting:  goodsFitting,
		GoodsTypeID:   goodsTypeID,
		GoodsContent:  goodsContent,
		Sort:          sort,
		Status:        status,
		AddTime:       int(time.Now().Unix()),
	}
	if err14 := DB.Create(&goods).Error; err14 != nil {
		context.String(http.StatusBadRequest, "商品增加失败")
		return
	}
	// 5. 增加图库信息
	wg.Add(1)
	go func() {
		defer wg.Done()
		goodsImageList := context.PostFormArray("goods_image_list")
		// 轮询创建记录
		for _, v := range goodsImageList {
			goodsImage := GoodsImage{
				GoodsID: goods.ID,
				ImgUrl:  v,
				Sort:    sort,
				Status:  status,
				AddTime: int(time.Now().Unix()),
			}
			if err15 := DB.Create(&goodsImage).Error; err15 != nil {
				context.String(http.StatusBadRequest, "创建失败")
				return
			}
		}
	}()
	// 6. 增加规格和包装(商品属性)
	wg.Add(1)
	go func() {
		defer wg.Done()
		attrIDList := context.PostFormArray("arr_id_list")
		attrValueList := context.PostFormArray("arr_value_list")
		for i := 0; i < len(attrIDList); i++ {
			attrID, err16 := strconv.Atoi(attrIDList[i])
			if err16 != nil {
				context.String(http.StatusBadRequest, "参数有误")
				return
			}
			// 检索对应的属性
			var goodsTypeAttribute GoodsTypeAttribute
			DB.Where("id = ?", attrID).Take(&goodsTypeAttribute)
			goodsAttr := GoodsAttr{
				GoodsID:         goods.ID,
				AttributeCateID: goodsTypeAttribute.CateID,
				AttributeID:     attrID,
				AttributeTitle:  goodsTypeAttribute.Title,
				AttributeType:   goodsTypeAttribute.AttrType,
				AttributeValue:  attrValueList[i],
				Sort:            10,
				Status:          1,
				AddTime:         int(time.Now().Unix()),
			}
			if err17 := DB.Create(&goodsAttr).Error; err17 != nil {
				context.String(http.StatusBadRequest, "参数有误")
				return
			}
		}
	}()
	wg.Wait() // 直到计数器归零, 才会继续向下执行
	context.JSON(http.StatusOK, gin.H{
		"success": true,
	})
}

// 获取所有的商品
func (g GoodsController) Index(context *gin.Context) {
	// 手动分页
	page, err1 := strconv.Atoi(context.Query("page"))
	if err1 != nil || page == 0 { // 防止传0
		page = 1
	}
	// 每页的检索条数
	pageSize := 8
	// 获取关键词
	keyword := context.Query("keyword") // 没有就是空串 ""
	//if len(keyword) == 0 {
	//	keyword = ""
	//}
	var goodsList []Goods
	DB.Where("is_delete = ?", 0).Where("title like ?", "%"+keyword+"%").Offset((page - 1) * pageSize).Limit(pageSize).Find(&goodsList)
	// 总记录数量
	var Count int64
	DB.Table("goods").Count(&Count)
	context.JSON(http.StatusOK, gin.H{
		"data":        goodsList,
		"totalPages:": math.Ceil(float64(Count) / float64(pageSize)),
		"page":        page,
	})
}

// 获取单个商品的信息
func (g GoodsController) GetOnlyGoods(context *gin.Context) {
	id, err1 := strconv.Atoi(context.Param("id"))
	if err1 != nil {
		context.String(http.StatusBadRequest, "参数有误")
		return
	}
	// 1. 获取商品
	var goods Goods
	DB.Where("id = ?", id).Take(&goods)
	// 2. 获取商品的所有图片
	var goodsImageList []GoodsImage
	DB.Where("goods_id = ?", id).Find(&goodsImageList)
	// 3. 获取商品的属性
	var goodsAttrList []GoodsAttr
	DB.Where("goods_id = ?", id).Find(&goodsAttrList)
	context.JSON(http.StatusOK, gin.H{
		"goods":            goods,
		"goods_image_list": goodsImageList,
		"goods_attr_list":  goodsAttrList,
		"prePage":          context.Request.Referer(), // 获取到上一页面的地址
	})
}

// 编辑商品信息
func (g GoodsController) Edit(context *gin.Context) {
	id, err12 := strconv.Atoi(context.Param("id"))
	// 1. 获取表单提交的数据
	title := context.PostForm("title")
	subTitle := context.PostForm("sub_title")
	goodsSn := context.PostForm("goods_sn")
	cateId, err1 := strconv.Atoi(context.PostForm("cate_id"))
	goodsNumber, err2 := strconv.Atoi(context.PostForm("goods_number"))
	price, err3 := strconv.ParseFloat(context.PostForm("price"), 64) // 将字符型转成float64类型的数据
	marketPrice, err4 := strconv.ParseFloat(context.PostForm("market_price"), 64)
	relationGoods := context.PostForm("relation_goods")
	goodsAttr := context.PostForm("goods_attr") // 额外属性
	goodsVersion := context.PostForm("goods_version")
	goodsGift := context.PostForm("goods_gift")
	goodsFitting := context.PostForm("goods_fitting")
	// 获取到的是切片
	goodsColor := context.PostFormArray("goods_color")
	goodsKeywords := context.PostForm("goods_keywords")
	goodsDesc := context.PostForm("goods_desc")
	goodsContent := context.PostForm("goods_content")
	isDelete, err5 := strconv.Atoi("is_delete")
	isHot, err6 := strconv.Atoi(context.PostForm("is_hot"))
	isBest, err7 := strconv.Atoi(context.PostForm("is_best"))
	isNew, err8 := strconv.Atoi(context.PostForm("is_new"))
	goodsTypeID, err9 := strconv.Atoi(context.PostForm("goods_type_id"))
	sort, err10 := strconv.Atoi(context.PostForm("sort"))
	status, err11 := strconv.Atoi(context.PostForm("status"))
	if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil || err7 != nil || err8 != nil || err9 != nil || err10 != nil || err11 != nil || err12 != nil {
		context.String(http.StatusBadRequest, "参数有误")
		return
	}
	// 获取字符串
	goodsColorStr := strings.Join(goodsColor, ",")

	// 3. 上传图片, 生成缩略图
	goodsImg, err14 := context.FormFile("goods_img")
	if err14 != nil {
		context.String(http.StatusBadRequest, "文件上传失败")
		return
	}
	fmt.Println(goodsImg.Filename)
	// 获取文件后缀
	extName := path.Ext(goodsImg.Filename)
	// 创建合法后缀map映射
	allowExtMap := map[string]bool{
		".jpg":  true,
		".jpeg": true,
		".png":  true,
		".gif":  true,
	}
	// 判断文件的合法性
	if _, ok := allowExtMap[extName]; !ok {
		context.String(http.StatusBadRequest, "文件不合法")
		return
	}
	// 获取当前日期
	day := time.Now().Format("20060102")
	// 指定文件存储目录
	dir := "./static/upload/" + day
	// 迭代创建目录
	os.MkdirAll(dir, 0666)
	// 获取当前时间戳的字符串形式
	fileName := strconv.FormatInt(time.Now().Unix(), 10) + extName // 不要忘记拼接后缀
	// 拼接文件路径
	dst := path.Join(dir, fileName)
	err15 := context.SaveUploadedFile(goodsImg, dst)
	if err15 != nil {
		context.String(http.StatusBadRequest, "文件保存失败")
		return
	}
	if GetOssStatus() != 1 {
		// 裁剪图片
		wg.Add(1)
		go func() {
			defer wg.Done()
			ResizeGoodsImage(dst)
		}()
	}
	// 检索特定商品
	var goods Goods
	DB.Where("id = ", id).Take(&goods)
	goods.Title = title
	goods.SubTitle = subTitle
	goods.GoodsSn = goodsSn
	goods.CateID = cateId
	goods.GoodsNumber = goodsNumber
	goods.Price = price
	goods.MarketPrice = marketPrice
	goods.RelationGoods = relationGoods
	goods.GoodsAttr = goodsAttr
	goods.GoodsVersion = goodsVersion
	goods.GoodsImg = dst
	goods.GoodsGift = goodsGift
	goods.GoodsFitting = goodsFitting
	goods.GoodsColor = goodsColorStr
	goods.GoodsKeywords = goodsKeywords
	goods.GoodsDesc = goodsDesc
	goods.GoodsContent = goodsContent
	goods.IsDelete = isDelete
	goods.IsHot = isHot
	goods.IsBest = isBest
	goods.IsNew = isNew
	goods.GoodsTypeID = goodsTypeID
	goods.Sort = sort
	goods.Status = status
	// 保存数据
	if err16 := DB.Save(&goods).Error; err16 != nil {
		context.String(http.StatusBadRequest, "修改失败")
		return
	}
	// 修改图库
	wg.Add(1)
	go func() {
		defer wg.Done()
		goodsImageList := context.PostFormArray("goods_image_list")
		for _, v := range goodsImageList {
			goodsImage := GoodsImage{
				GoodsID: id,
				ImgUrl:  v,
				Sort:    10,
				Status:  1,
				AddTime: int(time.Now().Unix()),
			}
			if err17 := DB.Create(&goodsImage).Error; err17 != nil {
				context.String(http.StatusBadRequest, "保持失败")
				return
			}
		}
	}()
	// 批量删除商品属性
	DB.Where("goods_id = ?", id).Delete(&GoodsAttr{})
	wg.Add(1)
	go func() {
		defer wg.Done()
		// 批量创建商品属性
		goodsAttrIdList := context.PostFormArray("goods_attr_id_list")
		goodsAttrValueList := context.PostFormArray("goods_attr_value_list")
		for i := 0; i < len(goodsAttrIdList); i++ {
			// 检索类型属性
			var goodsTypeAttr GoodsTypeAttribute
			DB.Where("id = ?", goodsAttrIdList[i]).Take(&goodsTypeAttr)
			// 类型转换
			goodsTypeAttrId, err18 := strconv.Atoi(goodsAttrIdList[i])
			if err18 != nil {
				context.String(http.StatusBadRequest, "参数有误")
				return
			}
			// 创建记录
			goodsAttr := GoodsAttr{
				GoodsID:         id,
				AttributeCateID: goodsTypeAttr.CateID,
				AttributeID:     goodsTypeAttrId,
				AttributeTitle:  goodsTypeAttr.Title,
				AttributeType:   goodsTypeAttr.AttrType,
				AttributeValue:  goodsAttrValueList[i],
				Sort:            10,
				Status:          1,
				AddTime:         int(time.Now().Unix()),
			}
			if err19 := DB.Create(&goodsAttr).Error; err19 != nil {
				context.String(http.StatusBadRequest, "修改失败")
				return
			}
		}
	}()
	wg.Wait()
	context.String(http.StatusOK, "修改成功")
}

// 修改商品图片颜色(GET)
func (g GoodsController) ChangeGoodsImageColor(context *gin.Context) {
	// 获取图片id
	goodsImageId, err1 := strconv.Atoi(context.Query("goods_image_id"))
	colorId, err2 := strconv.Atoi(context.Query("color_id"))
	if err1 != nil || err2 != nil {
		context.String(http.StatusBadRequest, "参数有误")
		return
	}
	// 检索图片
	var goodsImage GoodsImage
	DB.Where("id = ?", goodsImageId).Take(&goodsImage)
	goodsImage.ColorID = colorId
	if err3 := DB.Save(&goodsImage).Error; err3 != nil {
		context.String(http.StatusBadRequest, "参数有误")
		return
	}
	context.String(http.StatusOK, "更新成功")
}

// 删除商品图片
func (g GoodsController) RemoveGoodsImage(context *gin.Context) {
	// 获取商品图片id
	id, err1 := strconv.Atoi(context.Param("id"))
	if err1 != nil {
		context.String(http.StatusBadRequest, "参数有误")
		return
	}
	var goodsImage GoodsImage
	DB.Where("id = ?", id).Take(&goodsImage)
	if err2 := DB.Delete(&goodsImage).Error; err2 != nil {
		context.String(http.StatusBadRequest, "删除失败")
		return
	}
	context.String(http.StatusOK, "删除成功")
}

// 删除商品
func (g GoodsController) RemoveGoods(context *gin.Context) {
	id, err1 := strconv.Atoi(context.Param("id"))
	if err1 != nil {
		context.String(http.StatusBadRequest, "参数有误")
		return
	}
	// 检索商品
	var goods Goods
	DB.Where("id = ?", id).Take(&goods)
	goods.IsDelete = 1
	goods.Status = 0
	if err2 := DB.Save(&goods).Error; err2 != nil {
		context.String(http.StatusBadRequest, "删除出错")
		return
	}
	context.String(http.StatusOK, "删除成功")
}
